#!/usr/bin/python
# -*- coding=utf-8 -*-
import getopt
import sys
import os
import shutil
import time
import subprocess

class tdump:

    def __init__(self):
        self.dumpDir = "/home/ttx/app/toolbox/tdump"
        self.setEnv()
        self.pid = 0
        self.thread = False
        self.mem = False
        self.options()
        self.create_dir(self.dumpDir)
        self.clearDumpHisory()

    def setEnv(self):
        JAVA_HOME = '/home/ttx/app/jre'
        PATH = "%s/bin:%s" % (JAVA_HOME, os.environ['PATH'])
        CLASSPATH = ".:%s/lib/dt.jar:%s/lib/tools.jar" % (JAVA_HOME, JAVA_HOME)
        os.environ['JAVA_HOME'] = JAVA_HOME
        os.environ['PATH'] = PATH
        os.environ['CLASSPATH'] = CLASSPATH

    def exec_cmd(self,cmd):
        try:
            return subprocess.call(cmd, shell=True)
        except BaseException as e:
            print(e)
            return 1

    def create_dir(self,dir_path):
        if os.path.exists(dir_path):
            return
        os.makedirs(dir_path)

    def clearDumpHisory(self):
        shutil.rmtree(self.dumpDir)
        self.create_dir(self.dumpDir)

    def getTimeStr(self):
        return time.strftime("%Y-%m-%d-%H%M", time.localtime())

    def jstack(self):
        print("导出进程线程信息")
        jstacklog_path = os.sep.join([self.dumpDir, "jstack-%s-%s.log" % (self.pid, self.getTimeStr())])
        cmd = "jstack -l %s > %s" % (self.pid , jstacklog_path)
        return self.exec_cmd(cmd)

    def jinfo(self):
        print("导出进程运行的JVM参数")
        jinfolog_path = os.sep.join([self.dumpDir, "jinfo-%s-%s.log" % (self.pid, self.getTimeStr())])
        cmd = "jinfo -flags %s > %s" % ( self.pid , jinfolog_path)
        return self.exec_cmd(cmd)

    def jmap_heap(self):
        print("导出heap的概要信息，GC使用的算法，heap（堆）的配置及JVM堆内存的使用情况")
        jmap_heap_path = os.sep.join([self.dumpDir, "jmap_heap-%s-%s.log" % (self.pid , self.getTimeStr())])
        cmd = "jmap -heap %s > %s" % (self.pid , jmap_heap_path)
        return self.exec_cmd(cmd)

    def jmap_histo(self):
        print("导出每个class的实例数目,内存占用,类全名信息")
        jmap_histo_path = os.sep.join([self.dumpDir, "jmap_histo-%s-%s.log" % (self.pid , self.getTimeStr())])
        cmd = "jmap -histo %s > %s" % (self.pid , jmap_histo_path)
        return self.exec_cmd(cmd)

    def jmap_histo_live(self):
        print("导出每个class的实例数目,内存占用,类全名信息(只统计活的对象数量)")
        jmap_histo_live_path = os.sep.join([self.dumpDir, "jmap_histo_live-%s-%s.log" % (self.pid, self.getTimeStr())])
        cmd = "jmap -histo:live %s > %s" % (self.pid , jmap_histo_live_path)
        return self.exec_cmd(cmd)

    def jmap_dump(self):
        print("使用hprof二进制形式,输出jvm的heap内容到文件")
        jmap_dump_live_path = os.sep.join([self.dumpDir, "jmap_dump-%s-%s.hprof" % (self.pid , self.getTimeStr())])
        cmd = "jmap -dump:file=%s %s" % (jmap_dump_live_path, self.pid)
        return self.exec_cmd(cmd)

    def tips(self):
        print("===============================================================")
        print("\033[1;32m如果导出过程中发现错误（jinfo -flags,jmap -heap)\n"
              "若不需要此信息不影响其他导出，如需请切换root账户，执行以下命令：\n"
              "echo 0 > /proc/sys/kernel/yama/ptrace_scope\n"
              "注意切换回ttx,然后执行脚本即可正常"
              "\033[0m")
        print("===============================================================")

    def options(self):
        opts, args = getopt.getopt(sys.argv[1:], "tm", [""])
        for op, value in opts:
            if op in ("-t"):
                self.thread = True
            elif op in ("-m"):
                self.mem = True
        if self.pid == 0 and len(args) > 0:
            self.pid = args[0]
        self.validateOptions()

    def validateOptions(self):
        if self.pid ==0:
            print("pid未指定")
            self.usage()
            sys.exit()

    def usage(self):
        print("用法：python3 %s [-t][-m][-F] <pid>" % os.path.basename(__file__))
        print('-t：只导线程信息')
        print('-m：只导内存信息')
        print("导出信息存储位置：%s"%self.dumpDir)
        print("""eg:
            1. Python3 tdump.py 29273     # 导出进程29273的所有线程/内存信息
            2. Python3 ttc.py -t  29273    # 只导出线程信息
            3. Python3 ttc.py -m 29273    #只导出内存信息
        """)

    def exportMem(self):
        self.jmap_heap()
        self.jmap_histo()
        self.jmap_histo_live()
        self.jmap_dump()

    def process(self):
        self.tips()
        self.jinfo()
        if self.thread:
            self.jstack()
        elif self.mem:
            self.exportMem()
        else:
            self.jstack()
            self.exportMem()

tdump = tdump()
tdump.process()



